// $Id$
package cz.pd.projectbuilder.main.util;

import cz.pd.projectbuilder.main.listener.Listener;
import cz.pd.projectbuilder.main.listener.ProjektyListener;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 
 * @author diblik
 * @version $Revision$
 */
public class ListenersUtils {

//  private static List<Listener> projektyListeners = new ArrayList<Listener>();
  private static List<Listener> listeners = new ArrayList<Listener>();

  public static void addListener(Listener projektyListener) {
    listeners.add(projektyListener);
  }

  public static void removeListener(Listener projektyListener) {
    listeners.remove(projektyListener);
  }

  public static <T extends Listener> T fire(Class<T> clazz) {
    if (clazz == null) {
      throw new NullPointerException();
    }

    final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    final Class[] name = new Class[]{clazz};

    final Collection<T> resultLookupItems = (Collection<T>) getListeners(clazz);
    DefaultInvocationHandlerImpl defaultInvocationHandlerImpl = new DefaultInvocationHandlerImpl();
    return clazz.cast(Proxy.newProxyInstance(classLoader, name, defaultInvocationHandlerImpl.getInvocationHandler(
        resultLookupItems)));
  }

  private static <T extends Listener> List<T> getListeners(Class<T> clazz) {
    List<T> sublistListeners = new ArrayList<T>();

    for (Listener listener : listeners) {
      if (clazz.isAssignableFrom(listener.getClass())) {
        sublistListeners.add((T) listener);
      }
    }
    return sublistListeners;
  }

  public static class DefaultInvocationHandlerImpl<T> implements InvocationHandler {

    private Collection resultLookupItems;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      for (Object lookupObject : resultLookupItems) {
        method.invoke(lookupObject, args);
      }

      return null;
    }

    public InvocationHandler getInvocationHandler(Collection resultLookupItems) {
      this.resultLookupItems = resultLookupItems;
      return this;
    }
  }
}
